iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
自我挑戰組

Java SE系列 第 20

Day20:銀河帝國

  • 分享至 

  • xImage
  •  

Java 9開始推出了模組(Module)系統,讓Java的結構更為嚴謹,並且提升JVM載入類別的效率(就是我們常常import一大堆類別那邊)。

什麼叫做更為嚴謹呢?原本我們要取用其他類別時,只要在要取用的類別中import進被取用的類別就好了,剩下就是看修飾子看不看得到而已;而在module中,還要定義類別可以給那些其他模組取用
packageVsModule
上圖右側,當Square類別要import右邊的圈圈時就會失敗,因為右邊圈圈所屬的module沒有聲明要exports給Square所屬module,就會import不到。

除了要多定義要給誰用外,映射的機制也需要額外定義能被取用的範圍,原本映射的機制是可以無視封裝修飾子的:

package flour;
public class Wheat{}

package flour;
class Manufacturer{
    public String name;
    public Integer est;
}

package bread;
import flour.Wheat;
import flour.Manufacturer; // 這邊會報錯,因為修飾子的關係,bread看不到flour中的Manufacturer類別
public class Baguette{
    Class class = Class.forName("flour.Manufacturer");
    Field[] fields = class.getFields(); // 透過映射就可以拿到不該看到的Manufacturer類別的屬性
}

我們來看看module的語法:

module <this module name> {
  requires <other module names>;
  exports <packages of this module to other modules that require them>;
  opens <packages of this module to other modules via reflection>;
  uses <services provided by other modules>;
  provides <services to other modules> with <service implementations>;
  version <value>;
}
  • requires
module com.some {
  // requires java.base -> 這行會隱藏在所有的module中,代表引入Java SE的基礎classes。
  requires java.logging;
  requires transitive org.acme; // 任何引用com.some的module也會需要org.acme,所以宣告transitive時,引用com.some的module不用額外再引用org.acme。
  requires static com.foo; // 宣告static代表這個module只會在compile time用到
}
  • exports
package demos.a;
public class L {}

package demos.a;
class M {}

package demos.b;
public class N {}

package demos.c;
public class O {}

module demos{
  exports demos.a;
  exports demos.b to other;
}

module other{
  requires demos;
}
// module other可以引用到class L, class N;class M為default所以只能在demos.a這個package中被看見,class O所在的package demos.c沒有被module exports,所以也沒辦法被其他module看見。
  
module foo{
  requires demos;
}
// module foo可以引用到class L;class N只被exports給module other,所以這邊看不見class N。
  • opens
    語法規則與exports一模一樣,差別在於開放出來的package,裡面的class將不受封裝子的規定,只要被open出來,就算是private的class或variable,都可被所open的對象reflection到。
    還有加在module前面的open語法:
open module demos {}

這表示所有其他的module都將可以取用該module的package,這就相當於以往的package運作規則了。

  • uses & provides
    在談uses與provides以前,要先談談ServiceLoader。主要分為Service和Provider兩個角色,Service其實就是介面,而Provider就是實作介面的類別,以下就直接以Service與Provider當作module的名字(實際上取什麼都可以):

Service:

module service{
  exports service.a;
}

package service.a;
public interface L{}

Provider:

module provider{
  requires service;
  provides service.a.L with provider.b.M;
}
package provider.b;
public class M implements service.a.L{}

有了以上定義後,當有類別要使用這個Service時,在module中聲明要取用哪個Service,並在程式碼中透過ServiceLoader.load(Service類別),並呼叫.findFirst()找到第一個有提供該Service的Provider實作,或透過.iterator()找到需要的Provider:

module application{
  requires service;
  uses service.a.L;
}

public class Main{
  public static void main(String[] args){
    ServiceLoader<L> s1 = ServiceLoader.load(L.class);
    L l = s1.findFirst().get();
  }
}

上一篇
Day19:別說那麼多廢話,講重點
下一篇
Day21:人生跑馬燈
系列文
Java SE30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言